home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-11-13 | 56.5 KB | 1,761 lines |
-
-
- **** W A R N I N G ****
-
- The documentation for this program is typesetted exactly like the
- Borland manuals. When this documentation is converted to plain ascii
- it doesn't look very pretty. Especially graphics are distorted,
- don't see chapter 4.
-
- This manual is primarily intended to give you an idea of its
- contents. Registered users receive a printed and bound manual.
- Besides they receive the manual in postscript format on disk.
-
- **** ****
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Borland Pascal Debug Kit
- ─────────────────────────────────────────────────────────────────────────────
-
- Programming Guide
-
-
-
-
-
- Version 1.10
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- NederWare
- Burgerstraat 22
- 5311 CX Gameren
- The Netherlands
- compuserve: 100120,3121
- email: berend@beard.nest.nl
- fidonet: 2:281/527.23
-
-
- C O N T E N T S
-
- ───────────────────────────────────────────────────────────────────────────────
-
-
-
- Introduction Program with less pain 1 Chapter 5 Assertions 23
- Why this tool?........................ 1
- Features ............................. 1
- Part 2 Reference Manual
- What's in this manual ................. 2
- Typefaces used in this manual .......... 2
- Chapter 6 Pascal Debug kit
- How to contact NederWare ............ 3
- Reference 27
- Acknowledgements ................... 3
- Sample procedure .................... 27
- Archive constant...................... 27
- Assert procedure ..................... 28
- Part 1 User Manual
- Beep procedure....................... 28
- Chapter 1 Working with log files 7 BeepOff procedure.................... 28
- How to create or open a log file ......... 7 BeepOn procedure .................... 28
- How can you write information in the BrowserRecordSize variable............ 29
- log file .............................. 8 BrowsersOffset variable ...............29
- ClassesOffset variable .................29
- Chapter 2 Checking your memory 9 ClassRecordSize variable ..............29
- What you must do before MemCheck CMPB function ....................... 29
- can work ............................ 9 CMPW function ...................... 30
- Updating the standard library ........ 9 ConvMemLimit variable............... 30
- Recompiling the system unit ......... 10 CorrelationRecordSize variable .........30
- What MemCheck does ................ 10 CorrelationsOffset variable............. 30
- How to enable memory checking ....... 11 CPos function ........................ 30
- How MemCheck works ............... 11 CR constant .......................... 30
- MemCheck and DPMI................. 12 CreateBAK procedure ................. 31
- DataOffset variable ...................31
- Chapter 3 Post Mortem Debugger 13
- DateTime type ....................... 31
- What the Post Mortem debugger does ... 13
- DebugHeader variable ................ 31
- Using the Post Mortem Debugger....... 14
- DebugInfoStart variable ............... 31
- The Post-Mortem-Debugger under
- Delay variable........................ 32
- MS-Windows ........................ 16
- dfXXXX constants .................... 32
- Extra features under Windows ....... 16
- DirStr type........................... 32
- GPF's under Windows .............. 16
- Discard procedure .................... 32
- Chapter 4 TDInfo 17 DisposeSLink procedure............... 33
- How TDInfo models Borland's Debug DonePMD procedure.................. 33
- Information .......................... 17 DoneStrings procedure ................ 33
- Changes between Open Architecture DosCopy procedure................... 33
- names and TDInfo names.............. 19 DosDel procedure .................... 34
- How to make use of TDInfo ............ 20 DosDelay procedure .................. 34
- Initializing the TDInfo unit...........20 DosMove procedure .................. 34
- Getting information from a debug DosTouch procedure .................. 35
- symbol file......................... 20 DosWipe procedure ................... 35
- Getting line numbers.............. 21 DStream variable ..................... 36
- Getting procedures ............... 21 DumpStack variable .................. 36
- DumpStackProcedureType type ........ 36
-
-
- i
-
-
-
-
-
-
-
- Empty function....................... 36 LoadStrings procedure ................ 46
- ExtractStr function .................... 36 LogError procedure ................... 46
- ExtStr type........................... 36 LowCase function .................... 46
- FancyStr function ..................... 37 LowStr function ...................... 46
- FatalErrorText variable ................ 37 MaxConventionalMemoryBlock constant 46
- FCreate function...................... 37 MaxMemPtrs constant................. 46
- FDefaultExtension function ............ 37 MaxWord constant.................... 47
- ferr variable.......................... 37 MemberRecordSize variable............ 47
- FExpand function..................... 38 MembersOffset variable ............... 47
- FF constant .......................... 38 MemCheckReport procedure ........... 47
- FForceDir function.................... 38 memfXXXX constants ................. 47
- FForceExtension function .............. 38 Min function ......................... 48
- FileExist function ..................... 38 ModuleClassesOffset variable .......... 48
- FileRec type.......................... 38 ModuleClassRecordSize variable ....... 48
- fmXXXX constants .................... 39 ModuleRecordSize variable ............ 48
- FOpen function....................... 39 ModulesOffset variable................ 48
- FormatStr procedure .................. 39 NamesOffset variable ................. 49
- FormFeed constant.................... 39 NameStr type ........................ 49
- FTCopy function ..................... 40 NewSLink function ................... 49
- GetAddrStr function .................. 40 OverloadRecordSize variable........... 49
- GetDateStr function ................... 40 ParentRecordSize variable ............. 49
- GetEnv function ...................... 40 ParentsOffset variable .................49
- GetFileName function ................. 40 PathStr type.......................... 50
- GetLogicalAddr function .............. 40 PrintError variable ....................50
- GetObjMemory function............... 41 PrintErrorType type................... 50
- GetStr function ....................... 41 prnXXXX constants ................... 50
- GetTextFileName function ............. 41 PSLink type.......................... 51
- GetTickCount function ................ 41 Registers type ........................ 51
- GetTimeStr function................... 42 RepChar function..................... 51
- GetUniqueFileName function .......... 42 ReplaceStr procedure.................. 51
- HandleRunTimeError variable ......... 42 ReportFileName constant .............. 51
- HandleRunTimeErrorProcedureType type 42 RightJustify function ..................52
- HexB function........................ 42 rsGet function ........................ 52
- HexStr function ...................... 42 rsGet1 function ....................... 52
- InitBBError function .................. 43 rsGet2 function ....................... 52
- InitIntHandler procedure .............. 43 ScanB function ....................... 53
- InitObjMemory procedure ............. 43 ScanW function ...................... 53
- InitPMD procedure ................... 43 ScopeClassesOffset variable ............53
- IsDirectory function................... 44 ScopeClassRecordSize variable ......... 53
- IsFileOpen function ................... 44 ScopeRecordSize variable .............. 53
- IsValidPtr function.................... 44 ScopesOffset variable ................. 53
- LeadingZero function ................. 44 scXXXX constants..................... 53
- LeftJustify function ................... 45 SearchRec type ....................... 54
- LF constant .......................... 45 SegmentRecordSize variable ........... 54
- LineNumberRecordSize variable........ 45 SegmentsOffset variable ............... 54
- LineNumbersOffset variable ........... 45 SetHandleCount procedure ............ 54
-
-
- ii
-
-
-
-
-
-
-
- SmallDebugHeaderSize constant ....... 55 Methods........................... 67
- SmallEndianI procedure ............... 55 TObjMemory object ................... 67
- SmallEndianL procedure .............. 55 Fields .............................67
- SmallEndianW procedure.............. 55 Methods........................... 67
- SourceFileRecordSize variable .......... 55 TOverload type....................... 68
- SourceFilesOffset variable ............. 55 TParent type ......................... 68
- Spc function ......................... 56 TResourceCollection object............. 69
- Spoiled function ...................... 56 Methods........................... 69
- StrB function ......................... 56 TResourceFile object ..................69
- StrI function ......................... 56 Fields .............................69
- Strings variable....................... 56 Methods........................... 69
- StripSpc function ..................... 56 TResourceItem type................... 70
- StrL function ......................... 57 TrimRight function.................... 70
- StrR function......................... 57 TScope object ........................ 70
- StrResBufSize variable................. 57 Fields .............................70
- StrS function ......................... 57 Methods........................... 71
- StrW function ........................ 57 TScopeClass type ..................... 71
- stXXXX constants ..................... 57 TSegment object ...................... 71
- SymbolRecordSize variable ............ 58 Fields .............................71
- SymbolsOffset variable ................ 58 Methods........................... 72
- TBrowser object ...................... 58 TSLink type.......................... 73
- Fields ............................. 58 TSmartBufStream object ............... 73
- Methods........................... 59 Fields .............................73
- TClass object ......................... 59 Methods........................... 73
- Fields ............................. 59 TSourceFile object .................... 73
- Methods........................... 59 Fields .............................74
- TCorrelation object.................... 59 Methods........................... 74
- Fields ............................. 60 TSymbol object ....................... 74
- Methods........................... 60 Fields .............................74
- TDebugHeader type .................. 60 Methods........................... 74
- TDInfoPresent function................ 62 TType object ......................... 75
- TDriveStr type ....................... 62 Fields .............................76
- TextPrintError procedure .............. 62 Methods........................... 76
- TextRec type ......................... 63 TypeRecordSize variable............... 77
- tid voidXXXX constants ............... 63 TypesOffset variable ..................77
- TLineNumber object .................. 63 UpStr function ....................... 77
- Fields ............................. 63 ValB function......................... 77
- Methods........................... 63 valcode variable ...................... 77
- TMember object ...................... 63 ValHex function ...................... 77
- Fields ............................. 65 ValI function ......................... 78
- Methods........................... 65 ValL function......................... 78
- TModule object....................... 65 ValR function ........................ 78
- Fields ............................. 65 ValW function........................ 78
- Methods........................... 66 Warning procedure ................... 78
- TModuleClass type ................... 66 ZeroRightJustify function ..............79
- TObject object ........................ 67
-
-
- iii
-
-
-
-
-
-
-
- Appendix A Errors and omissions
- in Open Architecture
- Handbook 81
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- iv
-
-
-
-
-
-
-
-
- I N T R O D U C T I O N
- ───────────────────────────────────────────────────────────────────────────────
-
-
- Program with less pain
-
-
- Why this tool?
- ───────────────────────────────────────────────────────────────────────────────
- Once, I tracked down a bug that caused some strange and
- unpredictable behaviour. After finally having located the problem,
- it appeared that I had released a bigger block of memory than
- what I had previously allocated. Borland Pascal, naturally, didn't
- like this. Well, neither did I since, all in all, this bug took me 10
- hours to find and fix.
- Some time later, I encountered another bug that caused a
- behaviour which I remembered but all too well. At that stage I
- thought: let's put these 10 hours to some better use.
-
- That thought was the start of MemCheck, a utility that tracks
- memory allocations and deallocations. If you release too much
- memory or too little, MemCheck aborts your application, writing
- the address of the erroneous code to a log file.
- MemCheck has since been enhanced to write the name of the file
- and the line of code using TDInfo, a utility that accesses the Debug
- information, if present, in an executable file.
-
- The above mentioned tools, MemCheck, TDInfo and PMD, together
- with Assertions, a unit which provides you with C like assertions,
- form the Borland Pascal Debug Kit. It's my sincere hope that these
- tools will prove useful to Pascal programmers all around the
- world, helping them to develop bug-free programs easier and
- faster.
-
-
- Features
- ───────────────────────────────────────────────────────────────────────────────
- The Borland Pascal Debug Kit provides you with many things that
- make debugging easier. If you use these tools properly, you can
- even be sure that some bugs will not occur in your programs! For
- example, releasing more or less memory than previously allocated
- immediately halts your program and the offending line is written
- to a log file.
- In summary, the Borland Pascal Debug Kit gives you:
-
-
- Introduction 1
-
-
-
-
-
-
-
- ■ Allocation and deallocation tracking
- ■ A report of not deallocated memory after your program
- termination
- ■ A full stack dump (procedure names and parameters) if a
- run-time error occurs
- ■ C-like assertions to `fortify your subsystems'
-
-
- What's in this manual
- ───────────────────────────────────────────────────────────────────────────────
-
- This manual explains how to use the Borland Pascal Debug Kit. It
- doesn't tell you how to write Borland Pascal programs.
-
- The first part of this manual contains the following chapters:
-
- ■ Chapter 1, ``Using log files'', describes how to use log files to
- make debugging easier, especially when your program is
- running at a remote site.
- ■ Chapter 2, ``Memory Checker'', introduces the memory
- allocation and deallocation tracker and explains how to use it.
- ■ Chapter 3, ``Post Mortem Debugger'', describes how to get
- annotated stack dumps.
- ■ Chapter 4, ``TDInfo'', explains a unit which gives access to
- Borland's debug information.
- ■ Chapter 5, ``Assertions'', introduces you to assertions and how
- to use them in your programs.
-
- The second part of this manual is contains reference material for
- the source code supplied with the Borland Pascal Debug Kit.
-
-
- Typefaces used in this manual
- ───────────────────────────────────────────────────────────────────────────────
-
- This manual was typeset using LATE X2ε, converted to postscript
- using dvips, and printed on a HP Laserjet IV. All typefaces used in
- this manual are standard Postscript fonts. Their uses are as
- follows:
-
- The monospace typeface represents text as it appears on-screen or
- in a program. It is also used for anything you must type (e.g. BP to
- start up the Borland Pascal IDE).
-
- The boldface typeface is used in text for command line options.
-
- Italics is used to indicate identifiers that appear in text. They can
- represent terms that you can use as they are, or that you can think
-
-
- 2 Borland Pascal Debug Kit Manual
-
-
-
-
-
-
-
- up new names for (your choice, usually). They are also used to
- emphasize certain words, such as new terms.
-
- This typeface indicates a key on your keyboard. For example,
- ``Press Esc to exit this menu.''
-
- Key combinations produced by holding down one or more keys
- simultaneously are represented as Key1+Key2.
-
-
- How to contact NederWare
- ───────────────────────────────────────────────────────────────────────────────
-
- NederWare offers a variety of services to answer your questions
- about the Borland Pascal Debug Kit. Of course, this is only true for
- registered users. If you haven't registered yet, support shareware
- (and me and my family) by registering this Debug Kit today.
- We've made it very easy for you. You can register by CompuServe,
- fax, email or telephone. Please consult REGISTER.FRM for more
- details.
-
- CompuServe
-
- Subscribers to CompuServe can reach NederWare at 100120,3121.
- The latest version of the Borland Pascal Debug Kit is available in
- library 3 of the BPASCAL forum.
-
- Internet
-
- NederWare can be reached on the Internet through
- NederWare@beard.nest.nl or berend@beard.nest.nl. For the latest
- Debug Kit version, check-out garbo.uwasa.fi:/pc/turbopas.
-
- Fidonet
-
- NederWare can be reached on Fidonet at 2:281/527.23. The latest
- version of the Borland Pascal Debug Kit is also available at
- 2:281/527, Contrast BBS, The Netherlands. Its full international
- telephone number is +31 70-3234903. From Holland dial
- 070-3234903.
-
-
- Acknowledgements
- ───────────────────────────────────────────────────────────────────────────────
-
- First and foremost, many thanks to Stephen Maguire, who in his
- excellent book [Maguire93] showed us all that writing bug free
- (well, almost) code is possible. If you are serious about writing
- commercial software, read this book! It inspired me to put together
- all the pieces I had accumulated over the years in this package.
-
-
- Introduction 3
-
-
-
-
-
-
-
- Many thanks also to Andy McFarland, author of TDI, a utility that
- displays the contents of the debug information the the BP compiler
- appends to an executable. Andy generously provided me with the
- source of his utility, which gave me a jump start in developing my
- TDInfo unit. Andy can be reached at CompuServe as 71055,2743 or
- by email as amcfarl@ndlc.occ.uky.edu.
-
- Last but not least thanks to Dag Hovden
- (dhovden@runner.knoware.nl) for cleaning up this manual and
- improving its english. All remaining faults are mine.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 4 Borland Pascal Debug Kit Manual
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- P A R T
- ───────────────────────────────────────────────────────────────────────────────
-
- 1
-
-
-
- User Manual
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 5
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 6 Borland Pascal Debug Kit Manual
-
-
-
-
-
-
-
-
- C H A P T E R
- ───────────────────────────────────────────────────────────────────────────────
-
- 1
-
-
-
- Working with log files
-
-
- Log files form the basis of Post Mortem Debugging. Using log files
- means no more scribbling down error codes and addresses on a
- piece of paper when your program crashes because it's already all
- there, in the log file. This feature becomes especially useful when
- you use it in tandem with PMD, the Post Mortem Debugger,
- because PMD gives you a full symbolic stack dump. Try to write
- that down as it scrolls past you on the screen!
- Another benefit of using log files is that you know exactly what
- your program was up to when it crashed running at a customer
- site. No more long telephone conversations, simply ask the
- customer to modem (or mail) you the log file.
-
-
- How to create or open a log file
- ───────────────────────────────────────────────────────────────────────────────
- The unit BBError makes using log files easy. All you have to is to
- call InitBBError with the name of the logfile and a Boolean
- parameter saying to create or to open the log file if it already exists.
- The following program demonstrates this:
-
- program Test;
-
- uses
- BBError;
-
- begin
- writeln('Installing log file writing');
- InitBBError('TEST.LOG', TRUE);
- writeln('Done!');
- end.
-
- A call to the procedure InitBBError does two things:
-
- 1. It creates the log file if it does not exists or if the second
- parameter is FALSE. The file is opened in append mode if it
- exists and the second parameter is TRUE.
-
-
- Chapter 1, Working with log files 7
-
-
-
-
-
-
-
- 2. It installs an exit procedure which writes the error address and
- exit code to the log file if an error occurs.
- This exit procedure also dumps a stack trace to the log file with
- the addresses of all the callers that lead up to the code that
- caused the error.
-
-
- How can you write information in the log file
- ───────────────────────────────────────────────────────────────────────────────
-
- You can write your own data to the log file using the ferr text file
- variable by adding BBError to the USES statement of any unit that
- wants to write to the log file.
-
- Example:
-
- program WriteToferr;
-
- uses
- BBError;
-
- begin
- InitBBError('TEST.LOG', TRUE);
- writeln(ferr, 'This goes to the log file.');
- end.
-
- A second method is to call BBError's LogError procedure which
- first writes the current date and time to the log file and next any
- text you passed to it. Calling LogError is the preferred method.
-
- Example:
-
- program WriteToLogError;
-
- uses
- BBError;
-
- begin
- InitBBError('TEST.LOG', TRUE);
- LogError('This goes to the log file.');
- end.
-
-
-
-
-
-
-
-
-
-
- 8 Borland Pascal Debug Kit Manual
-
-
-
-
-
-
-
-
- C H A P T E R
- ───────────────────────────────────────────────────────────────────────────────
-
- 2
-
-
-
- Checking your memory
-
-
- Use the MemCheck unit, if you want to check if your allocations
- match your deallocations or if you want to check if you didn't
- overwrite memory before or after an allocated memory block. This
- chapter tells you how to use MemCheck and what MemCheck does.
-
-
- What you must do before MemCheck can work
- ───────────────────────────────────────────────────────────────────────────────
-
- Before you can use MemCheck you need to replace the standard
- SYSTEM unit by the SYSTEM unit supplied with the Borland
- Pascal Debug Kit. There are two cases:
-
- ■ If you always work with the Borland Pascal library TURBO.TPL,
- TPP.TPL or TPW.TPL, you need to replace the SYSTEM unit
- contained in the library by the supplied one. Below we will
- explain how to do this.
- ■ If you don't load the library at startup but instead link in the
- units as separate files, simply copy the supplied SYSTEM.TPx to
- the directory where you keep these units.
- ─────────────────────────────────────────────────────────────────────────────
- Updating the
- Replacing SYSTEM.TPx is quite easy. First remove the `old'
- standard library
- SYSTEM.TPU from TURBO.TPL (or TPP.TPL or TPW.TPL, please
- substitute as needed). You can do this with the following
- command:
-
- tpumover turbo -system
-
- Next install the new SYSTEM.TPU by:
-
- tpumover turbo +system.tpu
-
- To install the new SYSTEM.TPW in the windows library type:
-
- tpumover tpw +system.tpw
-
- Note: don't forget tot type the correct extension after sytem, e.g.
- .tpu, .tpp or .tpw!
-
-
- Chapter 2, Checking your memory 9
-
-
-
-
-
-
- ─────────────────────────────────────────────────────────────────────────────
- Recompiling the
- If you have the run-time library source, and if you want to
- system unit
- recompile the SYSTEM unit with our changes incorporated, you
- need to patch the original SYSTEM.PAS, HEAP.ASM and
- WMEM.ASM with the diff (i.e. difference) files SYSTEM.DIF,
- HEAP.DIF and WMEM.DIF. Please note: these files are new
- structure diff files, created with the GNU diff utility.
-
- You can use the GNU patch utility (we use the one coming with
- the DJGPP GNU C compiler port) to patch your run-time library
- source. For example, execute
-
- patch system.dif c:/bp/rtl/sys/system.pas
-
- to update the SYSTEM.PAS file in the C:/BP/RTL/SYS directory.
-
-
- What MemCheck does
- ───────────────────────────────────────────────────────────────────────────────
-
- The MemCheck unit checks for the following three bugs:
-
- ■ Attempts to dispose a pointer, specifying a size other than the
- value used when creating the pointer. This causes a program
- halt.
- ■ Allocating memory and never deallocating it (i.e. memory
- leakage). By calling MemCheckReport, you obtain a list of
- pointers still allocated together with the addresses in your
- program where these pointers were created.
- ■ Writing to memory that lies outside an allocated block of
- memory, i.e. before or after the block. This check is equivalent to
- the Range check ({$R+}) option for normal arrays. This bug also
- causes a program halt.
-
- The demo program TestMem demonstrates these three bugs.
- Execute TestMem and select one of the three options presented to
- you. Afterwards, see TESTMEM.LOG for choice 1 and 2, and
- MEMCHECK.RPT for choice 3.
-
- If you have appended debug information to your executable and if
- you have initialized the post mortem debugger, MemCheck will
- also print the source file, line number and procedure name where
- the error occured. This is also true for MEMCHECK.RPT. When
- debug informaton is appended, you will find in MEMCHECK.RPT
- the source file and line number file where the allocation occured
- and on the next indented line the source file and line number of
- the caller of that routine (if any).
-
-
-
-
- 10 Borland Pascal Debug Kit Manual
-
-
-
-
-
-
-
- How to enable memory checking
- ───────────────────────────────────────────────────────────────────────────────
-
- You enable MemCheck by placing it in the USES clause of your
- main program. No additional calls are needed. Please bear in
- mind that using MemCheck will cost you an extra 32 bytes per
- allocated memory block!
-
- Errors detected by MemCheck are normally printed to the screen. A
- much better alternative is to use MemCheck together with BBError,
- the log file unit. When you use BBError the errors will be written
- to a log file instead.
-
-
- How MemCheck works
- ───────────────────────────────────────────────────────────────────────────────
-
- MemCheck keeps track of every allocated pointer and the size
- associated with it. For each allocated pointer, 16 bytes are needed
- to store this information. The information itself is stored in a
- collection which can hold a maximum of 16384 pointers. It is easy
- to enlarge this but as yet, there has been no need for that. If you
- should need more, please let me know and I'll enhance MemCheck.
-
- If possible, MemCheck allocates 8 or 16 bytes more for every
- memory block than what your program asked for. Because the
- maximum memory block that can be allocated is 65536-8 bytes,
- MemCheck always checks if it is possible to allocate 8 or 16 bytes
- more.
-
- ■ If it is possible to allocate 16 bytes more, MemCheck is able to
- check for memory overwrites before and after your allocated
- memory block. MemCheck does this by filling the first and last 8
- bytes with the value 0CCh. When you dispose this memory
- block, MemCheck checks if these values are still there. If not,
- memory has been overwritten and MemCheck halts your
- program.
- ■ If it is possible to allocate only 8 bytes more, MemCheck only
- checks for overwrites at the end of your memory block.
-
- To recap: every pointer needs 16 bytes to store information about
- it plus an extra 16 (or 8) bytes to check for 'out of range' errors.
- Together, this accounts for the 32 (or 24) bytes extra per allocated
- block. Under protected mode or in Windows, this is not a serious
- problem. Under real mode, however, this could well be a serious
- obstacle in using MemCheck, especially if your application uses
- many, small memory blocks.
-
-
-
- Chapter 2, Checking your memory 11
-
-
-
-
-
-
-
- MemCheck and DPMI
- ───────────────────────────────────────────────────────────────────────────────
-
- When running under protected mode, as some of you may know,
- you can check for writing outside an allocated memory block by
- setting HeapLimit to zero. This will enable the processor's built-in
- segment checking. The problem with this approach is that you can
- easily run out of selectors, especially if you use MemCheck at the
- same time. As we've seen above, MemCheck allocates a 16 byte
- memory block from the heap for every pointer (and uses that block
- to store information about the pointer). With HeapLimit set to zero,
- every allocation actually costs you two selectors!
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 12 Borland Pascal Debug Kit Manual
-
-
-
-
-
-
-
-
- C H A P T E R
- ───────────────────────────────────────────────────────────────────────────────
-
- 3
-
-
-
- Post Mortem Debugger
-
-
- The Post Mortem Debugger gives you the ability to print full
- symbolic stack dumps when an error condition occurs in your
- program. This is a feature you will not want to miss as soon as you
- have used it to develop programs.
-
-
- What the Post Mortem debugger does
- ───────────────────────────────────────────────────────────────────────────────
-
- Currently, the name debugger is a bit of a misnomer. The Post
- Mortem Debugger does nothing more than hooking into the exit
- procedure chain and dumping the stack, with all procedure names
- and parameter values, to the log file if an error occurs.
- If you have enabled the Post Mortem Debugger, MemCheck writes
- actual source file names and line numbers instead of hexadecimal
- addresses when it creates its report of not disposed memory.
-
- An example of the log entries created when a program exits with a
- fatal error is:
-
- ** Program started on 1994-02-26 at 19:07:38 **
- Post Mortem Debugger (PMD) installed.
- 1994-02-26 19:07:38 Error 215 at 0001:0031
- 1994-02-26 19:07:38 TESTPMD.PAS (26) procedure
- InSide(100,0,0);
- 1994-02-26 19:07:38 *** Full stack dump ***
- TESTPMD.PAS (31) procedure
- TestError((Open,'TESTPMD.BAK'),test2);
- TESTPMD.PAS (44)
-
- This is the log file created if you run the TestPMD program.
-
- The advantage of a symbolic stack dump is great, perhaps far
- greater than you would expect. You find errors much faster due to
- the full stack trace created. Previously, you could only get such an
- overview when running inside the debugger. For a frequently
-
-
- Chapter 3, Post Mortem Debugger 13
-
-
-
-
-
-
-
- called procedure, failing perhaps only every 100th time, it is not
- really easy (or much fun) to use breakpoints to wait for the correct
- moment to halt and view the stack.
-
- The Post-Mortem debugger has one flaw which shows up
- sometimes. If the stack trace consists of near calls, PMD may not
- always be able to find the address. As soon as a far call occurs in
- the stack frame, the stack dump is correct from that point on.
- Currently we do not know how to fix this. Luckily this case occurs
- seldom.
-
-
- Using the Post Mortem Debugger
- ───────────────────────────────────────────────────────────────────────────────
-
- To use the Post Mortem Debugger, you need to include three units
- in your USES clause. And you need three calls to initialize these
- three units. The order in which you call these routines is
- important. The order in which they appear in the USES clause is
- not important.
-
- The three units are BBError, ObjMemory and PMD. The
- initialization routines in their correct oder are InitBBError,
- InitObjMemory and InitPMD.
-
- The program listed below, also available as TESTPMD.PAS on
- your distribution disk, demonstrates the Post Mortem Debugger.
-
- {$Q+}
- program TestPMD;
-
- uses
- BBError, BBUtil,
- Objects, ObjMemory,
- {$IFDEF Windows}
- WinCrt,
- {$ENDIF}
- PMD;
-
- type
- types = (test1, test2, test3);
-
-
- procedure TestError(var f : text; e : types);
-
- procedure InSide(o : TObjMemory);
- var
- w : word;
- d : word;
- begin
- w := 0;
-
-
- 14 Borland Pascal Debug Kit Manual
-
-
-
-
-
-
-
- w := w - 1;
- end;
-
- begin
- InSide(GetObjMemory(100, 0, memfAll)^);
- end;
-
-
- var
- f : text;
- begin
- writeln(prnCR, 'Post Mortem Debugger tester.');
-
- (* initialize *)
- InitBBError('TESTPMD.LOG', TRUE);
- InitObjMemory;
- InitPMD(dfStandard);
-
- (* and show the error *)
- Assign(f, 'TESTPMD.PAS');
- Reset(f);
- TestError(f, test2);
- end.
-
- As you can see, there are three initialization routines that must be
- called before PMD can be used: InitBBError to open or create a log
- file, InitObjMemory to initialize the memory management routines
- that PMD uses, and (finally) InitPMD to initialize the Post Mortem
- Debugger itself. The InitPMD procedure accepts certain flags on
- which the Post Mortem Debugger bases its behaviour. The default
- is dfStandard, you will get only a symbolic stack dump when an
- error occurs. If you specify the dfDataSeg flag as well
- (InitPMD(dfStandard + dfDataSeg) ) the datasegment is also dumped
- to the log file.
-
- Compile the example program with full debug information
- enabled by typing
-
- tpc -m -l -v testpmd
-
- at the Dos command line prompt. The program contains a
- delibarate error, namely an overflow bug (therefore it has to be
- compiled with {$Q+}).. Run it, then look at the created log file
- TESTPMD.LOG.
-
- To use PMD you need quite some free memory. For large
- programs this can be as much as 100K or even more. Under real
- mode, the Post Mortem Debugger uses EMS or XMS memory if
- that's available.
-
-
-
- Chapter 3, Post Mortem Debugger 15
-
-
-
-
-
-
-
- The Post-Mortem-Debugger under MS-Windows
- ───────────────────────────────────────────────────────────────────────────────
-
- Under MS-Windows the Post-Mortem debugger has some extra
- capabilities including the ability to give a stack dump when a gpf
- occurs.
- ─────────────────────────────────────────────────────────────────────────────
- Extra features
- When the PMD unit is included in a windows program, you get
- under Windows
- the following extra features: MS-Windows:
-
- ■ Any text send to OutputDebugString is written to the log file
- also.
- ■ Any error Windows displays, is written to the log file also.
- ■ If you make a parameter error when calling a Windows
- function, this is logged. Almost no need for WinScope or
- BoundsChecker anymore!
- ─────────────────────────────────────────────────────────────────────────────
- GPF's under
- GPF's are not caught under MS-Windows unlike under DPMI. If
- Windows
- your program crashes, Windows will still display the UAE dialog
- box. If you want a symbolic stack dump in this case, you need to
- call InstallIntHandler in the PMD unit.
-
- InstallIntHandler is not called by default, because I couldn't get it
- work right when using the debugger. Without the debugger,
- everything runs fine. When I use the debugger to examine a
- program, leave the debugger to go back to the IDE, edit something
- and recompile, I'm bombed back to Dos, or Windows just hangs. I
- would be indebted, if anyone has a fix for this.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 16 Borland Pascal Debug Kit Manual
-
-
-
-
-
-
-
-
- C H A P T E R
- ───────────────────────────────────────────────────────────────────────────────
-
- 4
-
-
-
- TDInfo
-
-
- The TDInfo unit is used by MemCheck and PMD to provide access
- to the debug info stored in your executable. Information about this
- debug info can be found in [Borland92]. You probably need this
- book if you want to use TDInfo yourself.
- Because this books contains quite a few errors, I refer the reader to
- appendix A where I've listed OA.TXT, a file containing bugs and
- omissions to chapter 4 of Borland's "Open Architecture Handbook
- for Pascal".
-
-
- How TDInfo models Borland's Debug Information
- ───────────────────────────────────────────────────────────────────────────────
-
- Since the presented information in [Borland92] is less than clear,
- I've used semantic principles (see [Bekke92]) to make the
- information contained in the debug symbol tables and their
- mutual relationships clearer. I'll explain the semantic approach
- using the Turbo Debug Semantic Model presented in figure 4.1.
- Semantic data modeling has two notions: types and relationships.
- Types are basic data elements. Types are not stand-alone, but are
- related to each other. As can be seen in figure 4.1, types are drawn
- as rectangles. Relationships between types are drawn as lines.
- A type can be related to another type in two ways:
- ■ When a type consists of other types we talk about an aggregated
- type.
- ■ When a type is a special kind of another type, we talk about a
- specialized type.
- Aggregation can be seen in the Browser type, the uppermost
- rectangle. Somewhat simplified, aggregation can be said to be
- equal to the Pascal record type. A record type has a name and
- consists of various fields. So does the Browser. Each Browser
- 1 to a SourceFile
- record in the symbol table consists of a pointer
- 1The Symbol table actually does not store pointers, but record numbers
-
-
- Chapter 4, TDInfo 17
-
-
-
-
-
-
-
-
-
-
-
-
-
- Figure 4.1
- Turbo Debug Semantic Browser
- Model
-
-
-
- LineNumber Correlation Symbol
-
- oe─────
-
-
- Type
- Scope
-
- ───────
-
-
- SourceFile Segment
-
-
-
-
- Module
-
-
-
-
- Name
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 18 Borland Pascal Debug Kit Manual
-
-
-
-
-
-
-
- record, a LineNumber record and a Symbol record. The latter
- record is also an aggregated type. It consists of a pointer to a
- Module record, a Name record, a Scope record and a Type record.
- There is no example of specialization in this figure, but
- specialization can be compared to inheritance in Turbo Pascal.
-
- The way the types (records) are drawn is also important. Read
- from top to bottom, we always find fixed properties, i.e. a Browser
- always contains a SourceFile. Read from bottom to top, we have
- optional properties. Take for example the type Module. A Module
- can have zero or more Segments. In the same way, a Scope can
- have zero or more Symbols.
-
- The relationships expressed in figure 4.1 show the ways you can
- access information. If you have a certain line number, you first
- have to search the correct LineNumber record. If you now want to
- know in which source file this line appears, then you must first go
- to the LineNumber's Correlation record and from there to the
- SourceFile. If you want to know the name of the SourceFile you've
- found, you can go directly from the SourceFile record to the Name
- record.
-
- In the semantic query language Xplain, we would express this as:
-
- get LineNumber its Correlation its SourceFile its Name.
-
- Note that you can also get the name of the source file in which the
- line number appears in by going through Correlation its Segment
- its Module and, finally, its Name.
-
-
- Changes between Open Architecture names and TD-
- Info names
- ───────────────────────────────────────────────────────────────────────────────
-
- The TDInfo unit tries to model the debug symbol information as
- semanticly correct as possible. Each type in TDInfo is prefixed with
- a `T'. Note that I have changed some names so that they are not
- consistent with [Borland92] (which is fairly liberal with naming
- conventions to say the least).
-
- A list of Open Architecture names and TDInfo names is presented
- below. The TDInfo names refer to objects. The names in the Open
- Architecture book refer to records. The types are listed in the order
- they appear in the Open Architecture handbook.
- Note that almost all fields in TDInfo's object are different from their
- corresponding names in the Open Architecture Handbook too.
-
-
- Chapter 4, TDInfo 19
-
-
-
-
-
-
- Table 4.1
- TDInfo name OA name
- List of corresponding TDInfo
- names and OA names TSymbol TSymbolRecord
- TModule TModuleHeader
- TSourceFile SourceFile
- TLineNumber Line number
- TScope Scope
- TSegment Segment info
- TCorrelation Typedef
- TType Type Rec
- TMember Struct offset rec
- TClass TParent Table (?)
- TParent TParent Table
- TOverload Overload
- TScopeClass TClassTable
- TModuleClass LocalClass
- TBrowser TDefinitionRecord
-
-
- How to make use of TDInfo
- ───────────────────────────────────────────────────────────────────────────────
-
- In this section some information is given how you can make use of
- the TDInfo unit yourself. The information is this section is not yet
- complete. You should really take a look at the sources of the PMD
- unit and the AnnotateLog program (see ANNLOG.PAS, only in
- the registered version of this program).
- ─────────────────────────────────────────────────────────────────────────────
- Initializing the
- Before you can make use of TDInfo, you need to initialize it by
- TDInfo unit
- calling the function TDInfoPresent. Pass TDInfoPresent a filename
- which contains debug information. This file may be a stand-alone
- symbol file created with TDStrip or an executable with debug
- information appended to it. TDInfoPresent returns TRUE when it
- has found debug information in the file. Only when it returns
- TRUE is it save to use the other objects of the TDInfo unit.
- ─────────────────────────────────────────────────────────────────────────────
- Getting information from a debug symbol
- You can almost always directly express a `semantic query' using
- TDInfo. To get the name of a module, you use TModule.ItsName.
- To get the scope of a symbol you say TSymbol.ItsScope. These
- ItsXXXX methods always return a pointer to the object that
- file
- corresponds with the name of the method.
-
- When you call an ItsXXXX method for the first time, a new object
- of that type is created. When you call the ItsXXXX method for the
- second time, this object is returned again, so an object is not
- created twice. You don't have to dispose these pointers, they are
- disposed by the provider when you dispose the provider, i.e. if
-
-
- 20 Borland Pascal Debug Kit Manual
-
-
-
-
-
-
-
- you have called TSymbol.ItsScope, TSymbol.Done disposes the
- allocated TScope object.
-
- Let's take a look at a basic example. Given an physical address,
- Getting line
- how can we display its the source file and line number? The first
- numbers
- thing we need to do is to turn physical addresses into logical
- addresses. This is done by calling GetLogicalAddr. A physical
- address goes in, a logical address comes out. Using this logical
- address we can now proceed to find the source file and line
- number. One approach would be to look the logical address up in
- a .MAP file. Much easier is it to use the debug information
- appended to an executable.
- We get the LineNumber by calling the constructor
- TLineNumber.AtAddr. For example:
-
- LineNumber := New(PLineNumber, AtAddr(Addr));
-
- LineNumber will be nil if no line number could be found. Else it
- will contain a pointer to a TLineNumber object. To display the line
- number we can write LineNumber^.Value. To get the name of the
- source file, see also figure 4.1, we say
- LineNumber^.ItsCorrelation^.ItsSourceFile^.ItsName.
-
- Getting procedures
- To get the procedure to which this line number belongs, we have
- to know that a procedure is a symbol. To find a symbol at a given
- address, we can use TSymbol.AtSegment. We need to pass it a
- PSegment and an address. Because we already have a line number
- (see the previous section), the segment is
- LineNumber^.ItsCorrelation^.ItsSegment. The address is simply
- the logical address. The AtSegment constructor does quite an
- amount of work. It searches all scope records belonging to a
- certain segment to find a scope which covers the given address. It
- does this by calling TSegment.FirstScopeThat. This repeatedly
- calls the passed function until this function returns true. If this
- function returns TRUE, TSegment.FirstScopeThat returns the
- scope record for which the function returned TRUE. Although this
- is not displayed in figure 4.1, there exists a certain specialization of
- Scope, which contains a pointer to a Symbol record.
- TSymbol.AtSegment checks if TSegment.FirstScopeThat has
- returned such a scope. If that's the case, TSymbol.AtSegment
- loads the correct symbol record from the debug symbol table and
- returns.
- With the Symbol we now have, we have the procedure or function
- to which this line number belongs. The name of the procedure or
-
-
- Chapter 4, TDInfo 21
-
-
-
-
-
-
-
- function is Symbol^.ItsName. To determine of we have a
- procedure or a function we look at the type of the symbol. If
- Symbol^.ItsType^.ReturnType = 1 we have a procedure , else we
- have a function.
-
- There is a lot more to say about TDInfo, but this should get you
- started. In the PMD.PAS, ANNLOG.PAS and MEMCHECK.PAS
- you find some other or more elaborated uses of TDInfo.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 22 Borland Pascal Debug Kit Manual
-
-
-
-
-
-
-
-
- C H A P T E R
- ───────────────────────────────────────────────────────────────────────────────
-
- 5
-
-
-
- Assertions
-
-
- Once you have acquainted yourself with Assertions, you will not
- want to be without them! The Assertions unit provided here,
- makes it easy for Borland Pascal programmers to use them. Add
- Assertions to the USES clause of any unit or program which wants
- to use assertions. In your code, simply call the procedure Assert
- with a Boolean value and a string containing the message to be
- printed if the Boolean value evaluates to FALSE. After the message
- has been printed (which means that the assertion failed), your
- program halts.
-
- Example program:
-
- program Example
-
- uses
- BBError,
- Assertions;
-
- begin
- InitBBError('TEST.LOG', TRUE);
- Assert(TRUE, 'This assertion passes.');
- Assert(FALSE, 'This assertion fails.');
- end.
-
- If you call InitBBError , the message is written to the log file as well.
- If you use the PMD unit (properly initialized!), Assert also prints a
- symbolic stack trace.
- You will probably want to use Assertions only in your test code,
- not in your production code. All Assertions take time and space,
- and some Assertions take quite a lot of time. That's no problem, or
- less of a problem, as long as you're working with test code, but
- your production code should be as fast as possible. Also, you
- shouldn't need assertions there.
- To conditionally include Assertions in your program, embrace
- calls to Assert within a pair of conditional defines. The example
- program then looks like this:
-
-
- Chapter 5, Assertions 23
-
-
-
-
-
-
-
-
- {$DEFINE Debug}
- program Example
-
- uses
- BBError
- {$IFDEF Debug}
- , Assertions
- {$ENDIF}
- ;
-
- begin
- InitBBError('TEST.LOG', TRUE);
- {$IFDEF Debug}
- Assert(TRUE, 'This assertion passes.');
- Assert(FALSE, 'This assertion fails.');
- {$ENDIF}
- end.
-
- If you enable the Debug directive, the Assertions are included. If
- you disable the Debug directive, they are not included.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 24 Borland Pascal Debug Kit Manual
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- P A R T
- ───────────────────────────────────────────────────────────────────────────────
-
- 2
-
-
-
- Reference Manual
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 25
-
-
- ***************************************
- E N D O F T H I S M A N U A L
- ***************************************
-
-
- The complete reference manual is distributed with the registered
- version only. Again, the reference manual looks exactly like to
- Borland reference manuals.
-
- The registered version manual also contains a list of bugs in the
- Borland Pascal Open Architecture Book, compiled by Andy McFarland.
-
-
-